﻿/* 2011/11/18 */
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Collections.ObjectModel;

namespace Cosmos.Shortcuts
{
    /// <summary>
    /// Represents the mouse gesture.
    /// </summary>
    public struct MouseGesture : IShortcutAction
    {
        private Direction[] _track;

        public MouseGesture(IEnumerable<Direction> track)
        {
            if (track is ICollection<Direction>)
            {
                ICollection<Direction> collection = (ICollection<Direction>)track;
                _track = new Direction[collection.Count];
                collection.CopyTo(_track, 0);
            }
            else
            {
                Collection<Direction> collections = new Collection<Direction>();
                foreach (Direction aDirection in track)
                {
                    collections.Add(aDirection);
                }
                _track = new Direction[collections.Count];
                collections.CopyTo(_track, 0);
            }
        }

        public MouseGesture(IEnumerable<MoveDirection> track)
        {
            Collection<Direction> collection = new Collection<Direction>();
            foreach (MoveDirection aDirection in track)
            {
                collection.Add(aDirection.Direction);
            }
            _track = new Direction[collection.Count];
            collection.CopyTo(_track, 0);
        }

        public MouseGesture(string escapeString)
            : this()
        {
            EscapeString = escapeString;
        }

        /// <summary>
        /// Determines whether this MouseGesture and a specified MouseGesture have the same value.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Equals(MouseGesture value)
        {
            if (_track.Length != value._track.Length)
                return false;

            for (int i = 0; i < _track.Length; i++)
                if (_track[i] != value._track[i])
                    return false;

            return true;
        }

        public override string ToString()
        {
            string[] directionText = new string[_track.Length];
            for (int i = 0; i < _track.Length; i++)
            {
                directionText[i] = _track[i].ToString();
            }
            return String.Join(", ", directionText);
        }

        public string[] GetDirectionStrings()
        {
            string[] directionStrings = new string[_track.Length];
            for (int i = 0; i < _track.Length; i++)
            {
                directionStrings[i] = _track[i].ToString();
            }
            return directionStrings;
        }

        public string[] GetDirectionSymbols()
        {
            string[] directionSymbols = new string[_track.Length];
            for (int i = 0; i < _track.Length; i++)
            {
                switch (_track[i])
                {
                    case Direction.Center: directionSymbols[i] = "*"; break;
                    case Direction.North: directionSymbols[i] = "↑"; break;
                    case Direction.West: directionSymbols[i] = "←"; break;
                    case Direction.South: directionSymbols[i] = "↓"; break;
                    case Direction.East: directionSymbols[i] = "→"; break;
                    case Direction.NorthWest: directionSymbols[i] = "*"; break;
                    case Direction.SouthWest: directionSymbols[i] = "*"; break;
                    case Direction.NorthEast: directionSymbols[i] = "*"; break;
                    case Direction.SouthEast: directionSymbols[i] = "*"; break;
                    default: directionSymbols[i] = "*"; break;
                }
            }
            return directionSymbols;
        }

        private string GenerateEscapeString()
        {
            StringWriter stringWriter = new StringWriter();
            XmlWriter xmlWriter = XmlWriter.Create(stringWriter, SimpleXmlSettings.WriterSettings);
            
            xmlWriter.WriteStartElement("Gesture");
            xmlWriter.WriteStartAttribute("Count");
            xmlWriter.WriteString(_track.Length.ToString());
            xmlWriter.WriteEndAttribute();
            foreach (Direction aDirection in _track)
            {
                xmlWriter.WriteStartElement("Direction");
                xmlWriter.WriteString(((int)aDirection).ToString());
                xmlWriter.WriteEndElement();
            }
            xmlWriter.WriteEndElement();

            xmlWriter.Flush();
            xmlWriter.Close();
            stringWriter.Flush();
            string result = stringWriter.ToString();
            stringWriter.Close();
            return result;
        }

        private void ParseEscapeString(string escapeString)
        {
            StringReader stringReader = new StringReader(escapeString);
            XmlReader xmlReader = XmlReader.Create(stringReader, SimpleXmlSettings.ReaderSettings);

            xmlReader.Read();
            int directionCount = Int32.Parse(xmlReader.GetAttribute("Count"));
            _track = new Direction[directionCount];
            if (directionCount > 0)
            {
                xmlReader.ReadStartElement("Gesture");
                for (int i = 0; i < directionCount; i++)
                {
                    xmlReader.ReadStartElement("Direction");
                    _track[i] = (Direction)xmlReader.ReadContentAsInt();
                    xmlReader.ReadEndElement();
                }
                xmlReader.ReadEndElement();
            }
            else
            {
                xmlReader.ReadStartElement("Gesture");
            }            

            xmlReader.Close();
            stringReader.Close();
        }

        public string EscapeString
        {
            get { return GenerateEscapeString(); }
            set { ParseEscapeString(value); }
        }

        /// <summary>
        /// Gets the count of directions in the track.
        /// </summary>
        public int DirectionCount
        {
            get { return _track.Length; }
        }

        /// <summary>
        /// Gets the mouse track.
        /// </summary>
        public ReadOnlyCollection<Direction> Track
        {
            get 
            {
                return Array.AsReadOnly<Direction>(_track);
            }
        }
    }
}
